/*********************************************************************************
 *      Copyright:  (C) 2024 LingYun<iot25@lingyun>
 *                  All rights reserved.
 *
 *       Filename:  socket_cnn.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(07/12/24)
 *         Author:  LingYun <iot25@lingyun>
 *      ChangeLog:  1, Release initial version on "07/12/24 18:01:52"
 *                 
 ********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/tcp.h> 

#include "socket_cnn.h"

int client_connect_to_server(char *ipaddr,int port)
{
	int					client_fd = -1;
	struct sockaddr_in	serv_addr;

	//创建客户端socket
	client_fd = socket(AF_INET,SOCK_STREAM,0);
	if(client_fd < 0)
	{
		printf("Create client_fd failure:%s\n",strerror(errno));
		return -1;
	}

	//设置服务器端的地址和端口
	memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);                  // 使用传入的端口号
	inet_pton(AF_INET,ipaddr, &serv_addr.sin_addr); // 使用传递的主机名

	// 连接服务器端
	if (connect(client_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
	{
		printf("Connect to server [%s:%d] failure: %s\n",ipaddr, port, strerror(errno));
        close(client_fd);
        return -1;
    }

	//printf("Connected to server [%s:%d] sucessfully\n",ipaddr, port);
	return client_fd;
}


int server_connect_to_client(int port)
{
	int						server_fd = -1;
	struct sockaddr_in 		serv_addr;
	int						reuse = 1;
	//创建服务器端socket
	server_fd = socket(AF_INET,SOCK_STREAM,0);
	if(server_fd < 0)
	{
		printf("Create server_fd failure:%s\n",strerror(errno));
		return -1;
	}

	//设置服务器端的地址和端口
	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(port);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

	//绑定地址
	if( bind(server_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
	{
		printf("Create socket failure: %s\n", strerror(errno));
        return -2;
	}

	//监听
	if( listen(server_fd,50) < 0)
	{
		printf("Listen failure:%s\n",strerror(errno));
		return -3;
	}

	return server_fd;
}


int write_data(int socket_fd,const char *data,int data_len)
{
	if( socket_fd < 0)
	{
		printf("Socket is not connected.\n");
		return -1;
	}

	int write_bytes = write(socket_fd,data,data_len);
	if( write_bytes < 0)
	{
		//printf("Send data failure:%s\n",strerror(errno));
		return -2;
	}
	return write_bytes;
}

int read_data(int socket_fd,const char *data,int data_len)
{
	int read_bytes = read(socket_fd,(void *)data,data_len);
	if( read_bytes < 0)
	{
		printf("Recevie data failure:%s\n",strerror(errno));
		return -1;
	}
	return read_bytes;
}

//判断连接状态，因为有可能socket_fd大于0时也会出现断开的情况，返回1已连接，0未连接，-1出错
int cnn_status(int socket_fd)
{
	struct tcp_info 	info;        // 存储 TCP 信息的结构体
    socklen_t 			len = sizeof(info); // 结构体长度

    if (socket_fd <= 0)
    {
		printf("Invalid socket.\n");
        return -1; // 套接字无效，返回-1
    }

    if (getsockopt(socket_fd, IPPROTO_TCP, TCP_INFO, &info, &len) == -1)
    {
		//检查是否是连接问题
		if( errno == ECONNRESET )
		{
			printf("conncted failure:%s.\n",strerror(errno));
			return -1;//连接重置，返回未连接
		}

        printf("Getsockopt failure:%s",strerror(errno)); // 打印错误信息
        return -1;  //其他错误，返回-1
    }

    if (info.tcpi_state == TCP_ESTABLISHED)
    {
        //printf("1111conncted to server.\n"); // 打印连接状态
        return 1; // 返回已连接
    }
    else
    {
        printf("Connected closed or not established.\n"); // 打印断开状态
        return 0; //连接未建立或以已关闭
	}
}

//重连机制
int cnn_retry(int *client_fd,char *ipaddr,int port)
{
	if(*client_fd != -1)
	{
		close_socket(*client_fd);
		*client_fd = -1;
	}

	int retry_count = 5;  // 最大重试次数
    int retry_delay = 3;  // 重试间隔
	int	total_wait_time = 0; //记录累计等待时间

    for (int i = 0; i < retry_count; i++)
    {
        printf("Reconnecting to server [%s:%d]... Attempt %d/%d\n", ipaddr, port, i + 1, retry_count);
        *client_fd = client_connect_to_server(ipaddr, port);
        if (*client_fd >= 0)  // 如果成功连接
        {
			printf("Reconnected successfully\n");
            return *client_fd;
        }

		total_wait_time += retry_delay ;

		if (total_wait_time >= 10)
		{
			printf("Total wait time exceeded 10 seconds, exiting retry loop\n");
            break;  // 如果累计等待时间超过10秒，退出重试循环
        }
        
        sleep(retry_delay);
    }

	printf("Failed to coonnect after %d attempts\n",retry_count);

	return -1;
}

void close_socket(int socket_fd)
{
	close(socket_fd);
}
